package org.mbds.wolf.http;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;

import org.ksoap2.SoapEnvelope;
import org.ksoap2.SoapFault;
import org.ksoap2.serialization.SoapObject;
import org.ksoap2.serialization.SoapPrimitive;
import org.ksoap2.serialization.SoapSerializationEnvelope;
import org.ksoap2.transport.HttpTransportSE;
import org.xmlpull.v1.XmlPullParserException;

public class SoapWebServiceCaller implements Runnable {

	private final static String SUFFIX_GET_WSDL = "?wsdl";
	public static final String URL_PORT_SEP = ":";
	public static final String SOAP_ACTION_PREFIX = "/";

	private static String hostUrl = null;
	private static int hostPort = -1;
	private static String path = null;
	private static String service = null;
	private static String namespace = null;
	private static int enveloppeVersion = SoapEnvelope.VER11; // SoapEnvelop.VER11
																// is SOAP
																// Version 1.1
																// constant
	private static HashMap<String, String> properties = null;
	private static SoapObject response = null;

	/*
	 * Lock to wait for server response
	 */
	private final static Object lock = new Object();

	/**
	 * Singleton
	 */
	private static SoapWebServiceCaller _instance = new SoapWebServiceCaller();

	public static SoapWebServiceCaller getInstance() {
		return _instance;
	};

	private SoapWebServiceCaller() {
	};

	/**
	 * call SOAP web service
	 * 
	 * @param enveloppeVersion
	 * @param hostUrl
	 * @param path
	 * @param namespace
	 * @param service
	 * @return response
	 */
	public synchronized SoapObject call(int enveloppeVersion, String hostUrl,
			String path, String namespace, String service) {
		return call(enveloppeVersion, hostUrl, -1, path, namespace, service,
				null);
	}

	/**
	 * call SOAP web service
	 * 
	 * @param enveloppeVersion
	 * @param hostUrl
	 * @param hostPort
	 * @param path
	 * @param namespace
	 * @param service
	 * @return response
	 */
	public synchronized SoapObject call(int enveloppeVersion, String hostUrl,
			int hostPort, String path, String namespace, String service) {
		return call(enveloppeVersion, hostUrl, hostPort, path, namespace,
				service, null);
	}

	/**
	 * call SOAP web service
	 * 
	 * @param hostUrl
	 * @param hostPort
	 * @param path
	 * @param namespace
	 * @param service
	 * @param properties
	 * @return response
	 */
	public synchronized SoapObject call(String hostUrl, int hostPort,
			String path, String namespace, String service,
			HashMap<String, String> properties) {
		return call(SoapEnvelope.VER11, hostUrl, hostPort, path, namespace,
				service, properties);
	}

	/**
	 * call SOAP web service
	 * 
	 * @param hostUrl
	 * @param hostPort
	 * @param path
	 * @param namespace
	 * @param service
	 * @param properties
	 * @return response
	 */
	public synchronized SoapObject call(String hostUrl, String path,
			String namespace, String service, HashMap<String, String> properties) {

		return call(SoapEnvelope.VER11, hostUrl, -1, path, namespace, service,
				properties);
	}

	/**
	 * call SOAP web service
	 * 
	 * @param hostUrl
	 * @param hostPort
	 * @param path
	 * @param namespace
	 * @param service
	 * @return response
	 */
	public synchronized SoapObject call(String hostUrl, int hostPort,
			String path, String namespace, String service) {
		return call(SoapEnvelope.VER11, hostUrl, hostPort, path, namespace,
				service, null);
	}

	/**
	 * call SOAP web service
	 * 
	 * @param hostUrl
	 * @param path
	 * @param namespace
	 * @param service
	 * @return response
	 */
	public synchronized SoapObject call(String hostUrl, String path,
			String namespace, String service) {
		return call(SoapEnvelope.VER11, hostUrl, -1, path, namespace, service,
				null);
	}

	/**
	 * call SOAP web service
	 * 
	 * @param enveloppeVersion
	 * @param hostUrl
	 * @param hostPort
	 * @param path
	 * @param namespace
	 * @param service
	 * @return response
	 */
	public synchronized SoapObject call(int enveloppeVersion, String hostUrl,
			int hostPort, String path, String namespace, String service,
			HashMap<String, String> properties) {

		SoapWebServiceCaller.enveloppeVersion = enveloppeVersion;
		SoapWebServiceCaller.hostUrl = hostUrl;
		SoapWebServiceCaller.hostPort = hostPort;
		SoapWebServiceCaller.path = path;
		SoapWebServiceCaller.namespace = namespace;
		SoapWebServiceCaller.service = service;
		SoapWebServiceCaller.properties = properties;

		// Run the request into a thread
		new Thread(this).start();

		// Wait the end of thread
		try {
			synchronized (lock) {
				lock.wait();
			}
		} catch (InterruptedException e) {
		}

		return response;
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		response = call();
		// Notify unlock waiting processes
		synchronized (lock) {
			lock.notify();
		}
	}

	/**
	 * call
	 * 
	 * @return
	 */
	private static SoapObject call() {
		if (hostUrl == null)
			return null;
		// URL of WSDL
		String url = hostUrl;
		if (hostPort != -1)
			url += URL_PORT_SEP + hostPort;
		if (path != null && path != "")
			url += SOAP_ACTION_PREFIX + path;
		url += SOAP_ACTION_PREFIX + SUFFIX_GET_WSDL;

		SoapObject response = null;

		try {
			SoapEnvelope envelope = new SoapEnvelope(enveloppeVersion);
			SoapObject request = new SoapObject(namespace, service);

			if (properties != null) {
				for (String mapKey : properties.keySet()) {
					request.addProperty(mapKey, properties.get(mapKey));
				}
			}

			envelope.bodyOut = request;
			HttpTransportSE transport = new HttpTransportSE(url);
			try {
				transport.call(namespace + SOAP_ACTION_PREFIX + service,
						envelope);
			} catch (IOException e) {
				e.printStackTrace();
			} catch (XmlPullParserException e) {
				e.printStackTrace();
			}
			if (envelope.bodyIn != null)
				response = (SoapObject) envelope.bodyIn;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return response;
	}

}
